DataFrame Methods
A DataFrame is an in-memory, tabular data structure designed for flexible data manipulation outside of the cube. It provides a powerful way to retrieve, transform, and analyze data from multiple sources, including SQL queries, Data Adapters, and dynamic system objects. DataFrames support operations similar to traditional tables but optimized for OneStream’s analytics workflows, allowing large datasets to be processed efficiently. DataFrames can also be converted to legacy types such as DataTable or DataSet for compatibility with existing and legacy processes.
This topic covers the following:
For information about IDataFrame, see IDataFrame Interface.
DataFrame NameSpace
To use a DataFrame in a rule, make sure the OneStream.Data.DataFrame and OneStream.Data.DataFrame.Abstractions NameSpaces are included.
C#:
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
VB:
Imports OneStream.Data.DataFrame;
Imports OneStream.Data.DataFrame.Abstractions;
Basic DataFrame Functions
The following BRApi.Database functions are available to create DataFrame objects: :
- GetDataFrame: Creates a DataFrame and populates it using a database query. See GetDataFrame.
- CreateDataFramewithColumns: Creates an empty table with column names. See CreateDataFramewithColumns.
- CreateDataFrame: Creates an empty table in memory that can be populated. See DataFrame Methods.
- CreateEmptyDataFrame: Creates an empty table. See CreateEmptyDataFrame.
GetDataFrame
BRApi.Database.GetDataFrame(dbConn, dataFrameName, sqlStatement, dbParamsInfos, useCommandTimeoutLarge)
Execute an SQL query and return a DataFrame instance. These parameters are used:
| Parameter | Type | Description |
|---|---|---|
| dbConn | DbConnInfo | Database connection to run the SQL select statement against. |
| dataFrameName | string | Name of the DataFrame. |
| sqlStatement | string | SQL statement to be executed. |
| dbParamInfos (optional) | List<DbParamInfo> | A list of DbParamInfo objects that can be used to substitute SQL parameter names prefixed with @ using the associated parameter value. |
| useCommandTimeoutLarge | bool | Switch used to indicate if the standard system large timeout value should be used for the statement execution. |
Example in C#
// get DataFrame using a query
var myFrame = BRApi.Database.GetDataFrame(dbConn, "myFrame", "SELECT * FROM MyTable", useLargeTimeout);
var myFrame = BRApi.Database.GetDataFrame(dbConn, "myFrame", "SELECT * FROM MyTable where E=@entity", myDbParamInfos, useLargeTimeout);
Example in VB:
' get DataFrame using a query
Dim myFrame = BRApi.Database.GetDataFrame(dbConn, "myFrame", "SELECT * FROM MyTable", useLargeTimeout)
Dim myFrame = BRApi.Database.GetDataFrame(dbConn, "myFrame", "SELECT * FROM MyTable WHERE E=@entity", myDbParamInfos, useLargeTimeout)
CreateDataFramewithColumns
BRApi.Database.CreateDataFramewithColumns(dataFrameName, columnsInfo)
Create a DataFrame with a specified set of columns. If the type of column data is not specified, it defaults to String. These parameters are used:
| Parameter | Type | Description |
|---|---|---|
| dataFrameName | string | Name of the DataFrame. |
| columnsInfos | List<string> or Dictionary<string, XFDataType> | A list of column names used for the DataFrame, or a dictionary where keys are column names and values are XFDataType constants that specify the type of data for each column. |
Example in C#:
// create empty DataFrame with columns
var myFrame = BRApi.Database.CreateDataFrameWithColumns("myFrame", colNames);
var myFrame = BRApi.Database.CreateDataFrameWithColumns("myFrame", colNamesAndTypesDict);
Example in VB:
' create empty DataFrame with columns
Dim myFrame2 = BRApi.Database.CreateDataFrameWithColumns("myFrame", colNames)
Dim myFrame2 = BRApi.Database.CreateDataFrameWithColumns("myFrame", colNamesAndTypesDict)
CreateEmptyDataFrame
BRApi.Database.CreateEmptyDataFrame(dataFrameName)
Produce an empty DataFrame with default properties. These parameters are used:
| Parameter | Type | Description |
|---|---|---|
| dataFrameName | string | Name of the DataFrame. |
Example in C#:
// create empty DataFrame
var myFrame = BRApi.Database.CreateEmptyDataFrame("myFrame") ;
Example in VB:
' create empty DataFrame
Dim myFrame1 = BRApi.Database.CreateEmptyDataFrame("myFrame")
Quickstart DataFrame Examples
The following snippets show a set of common techniques to work with DataFrames. Consult the class reference for the complete api description.
Convert DataFrame to Legacy Types
Use toDataTable(), toDataTable(), toDataTable(), and toDataTable() to convert data to a DataTable, XFDataTable, DataSet or RowsArray.
Example in C#:
// convert to DataTable
DataTable myDataTable = myDataFrame.toDataTable();
// convert to XFDataTable
XFDataTable myXFDataTable = myDataFrame.toXFDataTable();
// convert to DataSet
DataSet myDataSet = myDataFrame.toDataSet();
// convert to RowsArray
object[][] myNestedArray = myDataFrame.toRowsArray();
Example in VB:
' convert to DataTable
Dim DataTable As myDataTable = myDataFrame.toDataTable();
' convert to XFDataTable
Dim XFDataTable As myXFDataTable = myDataFrame.toXFDataTable();
' convert to DataSet
Dim DataSet As myDataSet = myDataFrame.toDataSet();
' convert to RowsArray
object[][] myNestedArray = myDataFrame.toRowsArray();
Get Metadata from DataFrame
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// metadata
int numColumns = myDataFrame.ColumnsCount;
int numRows = myDataFrame.RowCount;
string[] columnNames = myNewFrame.GetAllColumnNames();
Get DataFrame Column by Position
Get column data by name or ordinal position.
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// get columns by name or by ordinal position
DataFrameColumn myColumn = myNewFrame.GetColumn("Price");
DataFrameColumn myColumn = myNewFrame.GetColumn(3);
Assign Metadata to Columns
Use addColumn() to write metadata to columns.
Example in C#
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// columns carry metadata
Type colType = myColumn.Type;
string colName = myColumn.Name;
// define columns
myFrame.AddColumn(new DataFrameColumn<string>("colA"));
myFrame.AddColumn(new DataFrameColumn<int>("colB"));
Example in VB:
Imports OneStream.Data.DataFrame
Imports OneStream.Data.DataFrame.Abstractions
' columns carry metadata
Dim colType As Type = myColumn.Type
Dim colName As String = myColumn.Name
' define columns
myFrame.AddColumn(New DataFrameColumn(Of String)("colA"))
myFrame.AddColumn(New DataFrameColumn(Of Integer)("colB"))
Add and Retrieve Data
Use addRow() to write new rows with values to a DataFrame or GetColumn(), GetValue(), GetValueAsString(), or GetColumnOrdinal() to retieve data from a DataFrame.
Example in C#
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// add and retrieve data
object[] inValues = { "valueField1", 23};
myFrame.addRow(inValues);
for(int c = 0; c < df.ColumnsCount; c++){
for(int r = 0; r < df.RowCount; r++){
int myInt = (int) myFrame.GetColumn(c).GetValue(r)
string myStr = (string) myFrame.GetColumn(c).GetValueAsString(r);
}};
int myInt = (int) myFrame.GetValue(0, myFrame.GetColumnOrdinal("colB"));
Example in VB:
Imports OneStream.Data.DataFrame
Imports OneStream.Data.DataFrame.Abstractions
' add and retrieve data
Dim inValues As Object() = {"valueField1", 23}
myFrame.addRow(inValues)
For c As Integer = 0 To df.ColumnsCount - 1
For r As Integer = 0 To df.RowCount - 1
Dim myInt As Integer = CType(myFrame.GetColumn(c).GetValue(r), Integer)
Dim myStr As String = CType(myFrame.GetColumn(c).GetValueAsString(r), String)
Next
Next
Dim myInt As Integer = CType(myFrame.GetValue(0, myFrame.GetColumnOrdinal("colB")), Integer)
DataFrame Conversion
DataFrames can be sliced through conversion.
Example in C#:
var myFrame = BRApi.Database.GetDataFrame(...)
var options = DataFrameConversionOptions()
options.MaxRows = 100
options.StartRow = 10
var myXfDataTable = myFrame.ToXFDataTable(options)
Example in VB:
Dim myFrame = BRApi.Database.GetDataFrame(...)
Dim options As New DataFrameConversionOptions()
options.MaxRows = 100
options.StartRow = 10
Dim myXfDataTable = myFrame.ToXFDataTable(options)
Logs
Use ErrorLog.LogMessage() to write DataFrame content to the log.
Example in C#:
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// Convert the first 10 rows to string for logging
BRApi.ErrorLog.LogMessage(si, "DataFrame Test Output", myFrame.Peek(10));
Example in VB:
Imports OneStream.Data.DataFrame;
Imports OneStream.Data.DataFrame.Abstractions;
' Convert the first 10 rows to string for logging
BRApi.ErrorLog.LogMessage(si, "DataFrame Test Output", myFrame.Peek(10));
Create DataFrame from Data Adapter
Example in C#:
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
// Look up a Data Adapter and use its query – 9.1+
// note: requires PowerBI Connector support enabled
var myFrame = BRApi.Analytics.GetDataFrameForAdapter(si, isSystemLevel,
"myWorkspace", "myAdapter", "myResultTable", customSubstVars, null);
Example in VB:
Imports OneStream.Data.DataFrame;
Imports OneStream.Data.DataFrame.Abstractions;
// Look up a Data Adapter and use its query – 9.1+
// note: requires PowerBI Connector support enabled
Dim myFrame = BRApi.Analytics.GetDataFrameForAdapter(si, isSystemLevel,
"myWorkspace", "myAdapter", "myResultTable", customSubstVars, null);
Create a Dashboard DataSet Service
The following example implements a Dashboard DataSet using a few different techniques. The first and second datasets are generated by retrieving a table using GetDataFrame() and calling ToDataSet() to return a DataSet object. The last one creates a DataFrame using CreateDataFrameWithColumns() and then uses ToDataTable() to export a data table.
Example in C#:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.IO;
using System.Linq;
using Microsoft.CSharp;
using OneStream.Finance.Database;
using OneStream.Finance.Engine;
using OneStream.Shared.Common;
using OneStream.Shared.Database;
using OneStream.Shared.Engine;
using OneStream.Shared.Wcf;
using OneStream.Stage.Database;
using OneStream.Stage.Engine;
using OneStreamWorkspacesApi;
using OneStreamWorkspacesApi.V800;
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
{
public class DatasetWithDataFrame : IWsasDataSetV800
{
public object GetDataSet(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, DashboardDataSetArgs args)
{
try
{
if ((brGlobals != null) && (workspace != null) && (args != null))
{
if (args.DataSetName.XFEqualsIgnoreCase("HelloDataFrame")){
// simple query
bool useLargeCommandTimeout = false;
string frameName = "MyOutFrame";
string sql = "SELECT * FROM Dim"; // list all Dimensions
using(DbConnInfo dbConn = BRApi.Database.CreateApplicationDbConnInfo(si)){
// *** main call - execute SQL and return a dataframe ***
var myFrame = BRApi.Database.GetDataFrame(dbConn, frameName, sql, useLargeCommandTimeout);
// once we get the dataframe, convert it to legacy type that the rule expects
// Here you can use .ToDataTable() or .ToDataSet()
return myFrame.ToDataSet();
}
} else if(args.DataSetName.XFEqualsIgnoreCase("QueryWithParams")){
// query with parameters
// basic settings
bool useLargeCommandTimeout = false;
string frameName = "MyOutFrame";
string dimTypeStr = args.NameValuePairs.XFGetValue("Dim", "A");
bool isParent, isCube, isBRFN;
DimType dimTypeObj = DimType.GetItemFromAbbreviation(dimTypeStr,
out isParent, out isCube, out isBRFN);
// define parameters as names starting with @
string sql = "SELECT * FROM Dim WHERE DimTypeId = @dTypeId";
// associate your values to the param names
var myParams = new List<DbParamInfo>{
new DbParamInfo("dTypeId", dimTypeObj.Id)};
// execute
using(DbConnInfo dbConn = BRApi.Database.CreateApplicationDbConnInfo(si)){
// *** main call - execute SQL and return a dataframe ***
var myFrame = BRApi.Database.GetDataFrame(dbConn, frameName, sql, myParams, useLargeCommandTimeout);
// convert to expected legacy type
return myFrame.ToDataSet();
}
} else if(args.DataSetName.XFEqualsIgnoreCase("FromScratch")){
// specify type for each column (optional)
var columns = new Dictionary<string, XFDataType>{
{"Strings", XFDataType.Text},
{"Ints", XFDataType.Int32},
{"Bools", XFDataType.Boolean},
{"Datetimes", XFDataType.DateTime},
{"Decimals", XFDataType.Decimal},
{"Guids", XFDataType.Guid},
{"WeirdosAsString", XFDataType.WorkflowTrackingFrequency}
};
// create and populate dataframe
var myDf = BRApi.Database.CreateDataFrameWithColumns("Output Frame", columns);
myDf.AddRow(new object[]{ "My Text ", 42, true, DateTime.Now, 10.3m, Guid.Empty, WorkflowTrackingFrequency.HalfYearly });
// convert to expected legacy type
return myDf.ToDataTable();
}
}
return null;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
}
}
Example in VB:
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.Common
Imports System.Globalization
Imports System.IO
Imports System.Linq
Imports Microsoft.VisualBasic
Imports OneStream.Finance.Database
Imports OneStream.Finance.Engine
Imports OneStream.Shared.Common
Imports OneStream.Shared.Database
Imports OneStream.Shared.Engine
Imports OneStream.Shared.Wcf
Imports OneStream.Stage.Database
Imports OneStream.Stage.Engine
Imports OneStream.Data.DataFrame
Imports OneStream.Data.DataFrame.Abstractions
Imports OneStreamWorkspacesApi
Imports OneStreamWorkspacesApi.V800
Namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
Public Class DatasetWithDataFrame
Implements IWsasDataSetV800
Public Function GetDataSet(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, _
ByVal args As DashboardDataSetArgs) As Object Implements IWsasDataSetV800.GetDataSet
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) AndAlso (args IsNot Nothing) Then
' simple query
If args.DataSetName.XFEqualsIgnoreCase("HelloDataFrame") Then
Dim useLargeCommandTimeout As Boolean = False
Dim frameName As String = "MyOutFrame"
Dim sql As String = "SELECT * FROM Dim" ' List all Dimensions
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
' *** main call - execute SQL and return a dataframe ***
Dim myFrame = BRApi.Database.GetDataFrame(dbConn, frameName, sql, useLargeCommandTimeout)
' Once we get the dataframe, convert it to legacy type that the rule expects
' Here you can use .ToDataTable() or .ToDataSet()
Return myFrame.ToDataSet()
End Using
ElseIf args.DataSetName.XFEqualsIgnoreCase("QueryWithParams") Then
' query with parameters
' basic settings
Dim useLargeCommandTimeout As Boolean = False
Dim frameName As String = "MyOutFrame"
Dim dimTypeStr As String = args.NameValuePairs.XFGetValue("Dim", "A")
Dim isParent, isCube, isBRFN As Boolean
Dim dimTypeObj As DimType = DimType.GetItemFromAbbreviation(dimTypeStr, _
isParent, isCube, isBRFN)
' define parameters starting with @
Dim sql As String = "SELECT * FROM Dim WHERE DimTypeId = @dTypeId"
' associate your values to param names
Dim myParams = New List(Of DbParamInfo) From {
New DbParamInfo("dTypeId", dimTypeObj.Id)
}
' execute
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
' *** main call - execute SQL and return a dataframe ***
Dim myFrame = BRApi.Database.GetDataFrame(dbConn, frameName, sql, myParams, useLargeCommandTimeout)
' convert to expected legacy type
Return myFrame.ToDataSet()
End Using
ElseIf args.DataSetName.XFEqualsIgnoreCase("FromScratch") Then
' specify type for each column (optional, defaults to string otherwise)
Dim columns = New Dictionary(Of String, XFDataType) From {
{"Strings", XFDataType.Text},
{"Ints", XFDataType.Int32},
{"Bools", XFDataType.Boolean},
{"Datetimes", XFDataType.DateTime},
{"Decimals", XFDataType.Decimal},
{"Guids", XFDataType.Guid},
{"WeirdosAsString", XFDataType.WorkflowTrackingFrequency}
}
' create and populate dataframe
Dim myDf = BRApi.Database.CreateDataFrameWithColumns("Output Frame", columns)
myDf.AddRow(New Object() {"My Text ", 42, True, DateTime.Now, 10.3D, Guid.Empty, WorkflowTrackingFrequency.HalfYearly})
' convert to expected legacy type
Return myDf.ToDataTable()
End If
End If
Return Nothing
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
End Class
End Namespace
Create a Dynamic Grid
The following example shows how to create a Dynamic Grid Service by:
-
Using a custom table.
-
Populating default values if the table does not exist.
-
Writing data back to the table on edit.
Example in C#:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using OneStream.Finance.Database;
using OneStream.Finance.Engine;
using OneStream.Shared.Common;
using OneStream.Shared.Database;
using OneStream.Shared.Engine;
using OneStream.Shared.Wcf;
using OneStream.Stage.Database;
using OneStream.Stage.Engine;
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
using OneStreamWorkspacesApi;
using OneStreamWorkspacesApi.V800;
namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
{
public class DynamicGridWithDataFrame : IWsasDynamicGridV800
{
private string customTable = "XXX_DataFrameSamples";
public XFDynamicGridGetDataResult GetDynamicGridData(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, DashboardDynamicGridArgs args)
{
try
{
if ((brGlobals != null) && (workspace != null) && (args != null))
{
// create our dataframe
var df = GetOrCreateCustomTable(si, brGlobals, workspace, args);
// small hack to force formatting on Decimal column
// ** only necessary if dataframe is manually populated and used with Dynamic Grid
var amountColumnFormat = new XFDynamicGridColumnDefinition();
amountColumnFormat.ColumnName = "Amount";
amountColumnFormat.DataFormatString = "{0:C2}"; // currency, culture-specific symbol, 2 decimals
//amountColumnFormat.DataFormatString = "{0:N2}"; // generic number, no currency symbol, 2 decimals
var columnDefs = new List<XFDynamicGridColumnDefinition>{amountColumnFormat};
// convert to XFDataTable to set extra properties for our grid
XFDataTable xfDt = df.ToXFDataTable();
xfDt.Columns[0].IsPrimaryKeyColumn = true;
xfDt.HasPrimaryKeyColumns = true;
XFDynamicGridGetDataResult result = new XFDynamicGridGetDataResult(
xfDt, columnDefs, DataAccessLevel.AllAccess );
return result;
}
return null;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
public XFDynamicGridSaveDataResult SaveDynamicGridData(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, DashboardDynamicGridArgs args)
{
try
{
if ((brGlobals != null) && (workspace != null) && (args != null))
{
DashboardDynamicGridGetDataArgs getDataArgs = args.GetDataArgs;
DashboardDynamicGridSaveDataArgs saveDataArgs = args.SaveDataArgs;
if ((getDataArgs == null) || (saveDataArgs == null))
{
return null;
}
List<XFEditedDataRow> editedDataRows = saveDataArgs.EditedDataRows;
if (editedDataRows != null)
{
using (DbConnInfo dbConn = BRApi.Database.CreateApplicationDbConnInfo(si))
{
XFDataTableHelper.SaveRows(dbConn, "dbo", customTable, args.SaveDataArgs.Columns, true,
editedDataRows, true, true, true);
}
}
XFDynamicGridSaveDataResult result = new XFDynamicGridSaveDataResult();
result.DataTable = GetDynamicGridData(si, brGlobals, workspace, args)?.DataTable;
result.PageIndex = (getDataArgs.StartRowIndex / getDataArgs.PageSize);
result.IndexOfSelectedRowOnPage = 0;
result.SaveDataTaskResult = new XFDynamicGridSaveDataTaskResult()
{
IsOK = true,
ShowMessageBox = false,
Message = "Save Finished"
};
return result;
}
return null;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
/** utility method - Retrieve the contents of our custom table, or create and populate it with default values */
private IDataFrame GetOrCreateCustomTable(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, DashboardDynamicGridArgs args)
{
string sqlCheck = @"SELECT
CASE
WHEN EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG = DB_NAME()
AND TABLE_NAME = @customTableName
) THEN 1
ELSE 0
END as TableExists";
var sqlCheckParams = new List<DbParamInfo>{
new DbParamInfo("customTableName", customTable)
};
using(DbConnInfo dbConn = BRApi.Database.CreateApplicationDbConnInfo(si)){
// check if table already exists
var dfCheck = BRApi.Database.GetDataFrame(dbConn, "tableCheck", sqlCheck, sqlCheckParams, false);
if(Convert.ToBoolean(dfCheck.GetValue<int>(0,0))){
// table exists, return contents
return BRApi.Database.GetDataFrame(dbConn, "tableData", $"SELECT * FROM {customTable}", false);
} else {
// table does not exist, create it
var df = BRApi.Database.CreateDataFrameWithColumns(customTable,
new Dictionary<string, XFDataType>{
{"SKU", XFDataType.Int32},
{"Item", XFDataType.Text},
{"Amount", XFDataType.Decimal},
{"Added On", XFDataType.DateTime},
{"Available", XFDataType.Boolean},
{"RefreshFreq", XFDataType.WorkflowTrackingFrequency}
}
);
string sqlCreate = BuildSqlCreate(df, "SKU");
var createResult = BRApi.Database.ExecuteSql(dbConn, sqlCreate, false);
// populate it in memory
df.AddRow(1, "Lightsaber (green)", 1000m, DateTime.Now, true, WorkflowTrackingFrequency.Monthly);
df.AddRow(2, "Darth Helmet", 10000m, DateTime.Now, false, WorkflowTrackingFrequency.Yearly);
df.AddRow(3, "Bounty Hunter JetPack", 500m, DateTime.Now, true, WorkflowTrackingFrequency.Quarterly);
df.AddRow(4, "X-Wing", 200000000m, DateTime.Now, true, WorkflowTrackingFrequency.AllTimePeriods);
df.AddRow(5, "Sleaveless Vest", 50m, DateTime.Now, false, WorkflowTrackingFrequency.HalfYearly);
// convert it in order to use convenience calls for saving.
var dt = df.ToDataTable();
BRApi.Database.SaveCustomDataTable(si, "Application", customTable, dt, true, false);
// return contents
return df;
}
}
}
/** utility method - given a DataFrame, generate a CREATE statement */
private string BuildSqlCreate(IDataFrame df, string primaryColumn = null)
{
var sb = new StringBuilder();
sb.AppendLine($"CREATE TABLE [{df.Name}] (");
string primaryKeyCol = null;
foreach(var col in df.Columns)
{
// probably incomplete mapping, but covers the basics
string sqlType = col.Type == typeof(int) ? "INT"
: col.Type == typeof(string) ? "NVARCHAR(MAX)"
: col.Type == typeof(decimal) ? "DECIMAL(18,2)"
: col.Type == typeof(DateTime) ? "DATETIME"
: col.Type == typeof(bool) ? "BIT"
: "NVARCHAR(MAX)"; // default fallback
sb.Append($" [{col.Name}] {sqlType}");
// If this is the primary key column and integer, set as IDENTITY and NOT NULL
if ((primaryColumn != null) && col.Name.XFEqualsIgnoreCase(primaryColumn))
{
sb.Append(" IDENTITY(1,1) NOT NULL");
primaryKeyCol = col.Name;
}
else if (!col.Nullable)
{
sb.Append(" NOT NULL");
}
sb.Append(",");
sb.AppendLine();
}
// remove last ",\n" -- cross-platform way
int trimLength = Environment.NewLine.Length + 1;
sb.Remove(sb.Length - trimLength, trimLength );
if (!string.IsNullOrEmpty(primaryKeyCol))
{
sb.AppendLine($", CONSTRAINT [PK_{df.Name}] PRIMARY KEY ([{primaryKeyCol}])");
}
sb.Append(");");
return sb.ToString();
}
}
}
Example in VB:
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.Common
Imports System.Globalization
Imports System.IO
Imports System.Linq
Imports Microsoft.VisualBasic
Imports OneStream.Finance.Database
Imports OneStream.Finance.Engine
Imports OneStream.Shared.Common
Imports OneStream.Shared.Database
Imports OneStream.Shared.Engine
Imports OneStream.Shared.Wcf
Imports OneStream.Stage.Database
Imports OneStream.Stage.Engine
Imports OneStream.Data.DataFrame
Imports OneStream.Data.DataFrame.Abstractions
Imports OneStreamWorkspacesApi
Imports OneStreamWorkspacesApi.V800
Namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
Public Class DynamicGridWithDataFrame
Implements IWsasDynamicGridV800
Private customTable As String = "XXX_DataFrameSamples"
Public Function GetDynamicGridData(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, _
ByVal args As DashboardDynamicGridArgs) As XFDynamicGridGetDataResult Implements IWsasDynamicGridV800.GetDynamicGridData
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) AndAlso (args IsNot Nothing) Then
' create our dataframe -- see function further down
Dim df = GetOrCreateCustomTable(si, brGlobals, workspace, args)
' small hack to force formatting on Decimal column
' ** only necessary if dataframe is manually populated and used
Dim amountColumnFormat = New XFDynamicGridColumnDefinition()
amountColumnFormat.ColumnName = "Amount"
amountColumnFormat.DataFormatString = "{0:C2}" ' currency, culture-specific symbol, 2 decimals
' amountColumnFormat.DataFormatString = "{0:N2}"; ' generic number, no currency symbol, 2 decimals
Dim columnDefs = New List(Of XFDynamicGridColumnDefinition) From {
amountColumnFormat
}
' Convert to XFDataTable to set extra properties for our grid
' Hopefully unnecessary in future releases...
Dim xfDt As XFDataTable = df.ToXFDataTable()
xfDt.Columns(0).IsPrimaryKeyColumn = True
xfDt.HasPrimaryKeyColumns = True
Dim result As XFDynamicGridGetDataResult = New XFDynamicGridGetDataResult(xfDt, columnDefs, DataAccessLevel.AllAccess)
Return result
End If
Return Nothing
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
Public Function SaveDynamicGridData(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, _
ByVal args As DashboardDynamicGridArgs) As XFDynamicGridSaveDataResult Implements IWsasDynamicGridV800.SaveDynamicGridData
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) AndAlso (args IsNot Nothing) Then
Dim getDataArgs As DashboardDynamicGridGetDataArgs = args.GetDataArgs
Dim saveDataArgs As DashboardDynamicGridSaveDataArgs = args.SaveDataArgs
If (getDataArgs Is Nothing) OrElse (saveDataArgs Is Nothing) Then
Return Nothing
End If
Dim editedDataRows As List(Of XFEditedDataRow) = saveDataArgs.EditedDataRows
If editedDataRows IsNot Nothing Then
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
XFDataTableHelper.SaveRows(dbConn, "dbo", customTable, args.SaveDataArgs.Columns, True, editedDataRows, True, True, True)
End Using
End If
Dim result As XFDynamicGridSaveDataResult = New XFDynamicGridSaveDataResult()
result.DataTable = GetDynamicGridData(si, brGlobals, workspace, args)?.DataTable
result.PageIndex = (getDataArgs.StartRowIndex / getDataArgs.PageSize)
result.IndexOfSelectedRowOnPage = 0
result.SaveDataTaskResult = New XFDynamicGridSaveDataTaskResult() With {
.IsOK = True,
.ShowMessageBox = False,
.Message = "Save Finished"
}
Return result
End If
Return Nothing
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
' ** utility method - Retrieve the contents of our custom table, or create and populate it with default values.
Private Function GetOrCreateCustomTable(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, ByVal args As DashboardDynamicGridArgs) As IDataFrame
Dim sqlCheck As String = "SELECT
CASE
WHEN EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG = DB_NAME()
AND TABLE_NAME = @customTableName
) THEN 1
ELSE 0
END as TableExists"
Dim sqlCheckParams = New List(Of DbParamInfo) From {
New DbParamInfo("customTableName", customTable)
}
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
' check if table already exists
Dim dfCheck = BRApi.Database.GetDataFrame(dbConn, "tableCheck", sqlCheck, sqlCheckParams, False)
If Convert.ToBoolean(dfCheck.GetValue(Of Integer)(0, 0)) Then
' table exists, return contents
Return BRApi.Database.GetDataFrame(dbConn, "tableData", $"SELECT * FROM {customTable}", False)
Else
' table does not exist yet, create it
Dim df = BRApi.Database.CreateDataFrameWithColumns(customTable, New Dictionary(Of String, XFDataType) From {
{"SKU", XFDataType.Int32},
{"Item", XFDataType.Text},
{"Amount", XFDataType.Decimal},
{"Added On", XFDataType.DateTime},
{"Available", XFDataType.Boolean},
{"RefreshFreq", XFDataType.WorkflowTrackingFrequency}
})
Dim sqlCreate As String = BuildSqlCreate(df, "SKU")
Dim createResult = BRApi.Database.ExecuteSql(dbConn, sqlCreate, False)
' populate it in memory
df.AddRow(1, "Lightsaber (green)", 1000D, DateTime.Now, True, WorkflowTrackingFrequency.Monthly)
df.AddRow(2, "Darth Helmet", 10000D, DateTime.Now, False, WorkflowTrackingFrequency.Yearly)
df.AddRow(3, "Bounty Hunter JetPack", 500D, DateTime.Now, True, WorkflowTrackingFrequency.Quarterly)
df.AddRow(4, "X-Wing", 200000000D, DateTime.Now, True, WorkflowTrackingFrequency.AllTimePeriods)
df.AddRow(5, "Sleaveless Vest", 50D, DateTime.Now, False, WorkflowTrackingFrequency.HalfYearly)
' convert it in order to use convenience calls for saving
Dim dt = df.ToDataTable()
BRApi.Database.SaveCustomDataTable(si, "Application", customTable, dt, True, False)
' return contents
Return df
End If
End Using
End Function
' utility method - given a DataFrame, generate a CREATE statement
Private Function BuildSqlCreate(ByVal df As IDataFrame, ByVal Optional primaryColumn As String = Nothing) As String
Dim sb = New StringBuilder()
sb.AppendLine($"CREATE TABLE [{df.Name}] (")
Dim primaryKeyCol As String = Nothing
For Each col In df.Columns
' probably incomplete mapping, but covers the basics well
Dim sqlType As String = _
If(col.Type = GetType(Integer), "INT", _
If(col.Type = GetType(String), "NVARCHAR(MAX)", _
If(col.Type = GetType(Decimal), "DECIMAL(18,2)", _
If(col.Type = GetType(DateTime), "DATETIME", _
If(col.Type = GetType(Boolean), "BIT", _
"NVARCHAR(MAX)"))))) ' default fallback
sb.Append($" [{col.Name}] {sqlType}")
' If this is the primary key column and integer, set as IDENTITY and NOT NULL
If (primaryColumn IsNot Nothing) AndAlso col.Name.XFEqualsIgnoreCase(primaryColumn) Then
sb.Append(" IDENTITY(1,1) NOT NULL")
primaryKeyCol = col.Name
ElseIf Not col.Nullable Then
sb.Append(" NOT NULL")
End If
sb.Append(",")
sb.AppendLine()
Next
' remove last ",\n" -- cross-platform way
Dim trimLength as Integer = Environment.NewLine.Length + 1
sb.Remove(sb.Length - trimLength, trimLength )
If Not String.IsNullOrEmpty(primaryKeyCol) Then
sb.AppendLine($", CONSTRAINT [PK_{df.Name}] PRIMARY KEY ([{primaryKeyCol}])")
End If
sb.Append(");")
Return sb.ToString()
End Function
End Class
End Namespace
Create a Table View
The following example creates a TableView Service using a DataFrame
Example in C#
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.IO;
using System.Linq;
using Microsoft.CSharp;
using OneStream.Finance.Database;
using OneStream.Finance.Engine;
using OneStream.Shared.Common;
using OneStream.Shared.Database;
using OneStream.Shared.Engine;
using OneStream.Shared.Wcf;
using OneStream.Stage.Database;
using OneStream.Stage.Engine;
using OneStream.Data.DataFrame;
using OneStream.Data.DataFrame.Abstractions;
using OneStreamWorkspacesApi;
using OneStreamWorkspacesApi.V800;
/**
Sample TableView implemented with DataFrame.
**/
namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
{
public class TableViewWithDataFrame : IWsasTableViewV800
{
public TableView GetTableView(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, string tableViewName, Dictionary<string, string> customSubstVars, Dictionary<string, string> nameValuePairs)
{
try {
if ((brGlobals != null) && (workspace != null)) {
if (tableViewName.XFEqualsIgnoreCase("DataFrame")) {
using(DbConnInfo dbConn = BRApi.Database.CreateApplicationDbConnInfo(si)){
// retrieve your data
IDataFrame df = BRApi.Database.GetDataFrame(dbConn,
"MyTableView", "SELECT * FROM Dim", false);
// build the tableview
TableView tv = new TableView();
// set up headers
foreach(var col in df.Columns){
// set basic info
var tvCol = new TableViewColumn();
tvCol.Name = col.Name;
tvCol.Value = col.Name;
tvCol.IsHeader = true;
// set the datatype
tvCol.DataType = XFDataTypeHelper.GetXFDataTypeFromDotNetDataType(si, col.Type);
// add to table
tv.Columns.Add(tvCol);
}
// Loop through rows to populate table
// Note how we keep track of the row index:
// values belong to *columns*, so to find them we ask a column to "go down X cells".
// Alternatively, we could keep track of the column position too,
// and use df.GetValue(colIndex, rowIndex), but it's more work.
foreach(var item in df.Rows.Select((row, index) => new {row, index})){
var tvr = new TableViewRow();
foreach(var col in df.Columns){
// TableViews want strings everywhere, so we use GetValueAsString.
// In other situation, we could use GetValueAsObject and cast it to the right type.
var tvrc = tv.CreateColumn(col.Name, col.GetValueAsString(item.index), false, true);
tvr.Items.Add(col.Name, tvrc);
}
tv.Rows.Add(tvr);
}
return tv;
}
}
}
return null;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
public List<string> TableViewGetCustomSubstVarsInUse(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, string tableViewName, Dictionary<string, string> custSubstVarsAlreadyResolved)
{
try
{
if ((brGlobals != null) && (workspace != null))
{
if (tableViewName.XFEqualsIgnoreCase("DataFrame"))
{
}
}
return null;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
public bool SaveTableView(SessionInfo si, BRGlobals brGlobals, DashboardWorkspace workspace, string tableViewName, TableView tableView)
{
try
{
if ((brGlobals != null) && (workspace != null) && (tableView != null))
{
if (tableViewName.XFEqualsIgnoreCase("MyTableView"))
{
}
}
return false;
}
catch (Exception ex)
{
throw new XFException(si, ex);
}
}
}
}
Example in VB:
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.Common
Imports System.Globalization
Imports System.IO
Imports System.Linq
Imports Microsoft.VisualBasic
Imports OneStream.Finance.Database
Imports OneStream.Finance.Engine
Imports OneStream.Shared.Common
Imports OneStream.Shared.Database
Imports OneStream.Shared.Engine
Imports OneStream.Shared.Wcf
Imports OneStream.Stage.Database
Imports OneStream.Stage.Engine
Imports OneStream.Data.DataFrame
Imports OneStream.Data.DataFrame.Abstractions
Imports OneStreamWorkspacesApi
Imports OneStreamWorkspacesApi.V800
Namespace Workspace.__WsNamespacePrefix.__WsAssemblyName
Public Class TableViewWithDataFrame
Implements IWsasTableViewV800
Public Function GetTableView(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, ByVal tableViewName As String, ByVal customSubstVars As Dictionary(Of String, String), _
ByVal nameValuePairs As Dictionary(Of String, String)) As TableView Implements IWsasTableViewV800.GetTableView
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) Then
If tableViewName.XFEqualsIgnoreCase("DataFrame") Then
Using dbConn As DbConnInfo = BRApi.Database.CreateApplicationDbConnInfo(si)
' retrieve your data
Dim df As IDataFrame = BRApi.Database.GetDataFrame(dbConn, _
"MyTableView", "SELECT * FROM Dim", False)
' build the tableview
Dim tv As TableView = New TableView()
' set up headers
For Each col In df.Columns
' set basic info
Dim tvCol = New TableViewColumn()
tvCol.Name = col.Name
tvCol.Value = col.Name
tvCol.IsHeader = True
' set datatype
tvCol.DataType = XFDataTypeHelper.GetXFDataTypeFromDotNetDataType(si, col.Type)
' add to table
tv.Columns.Add(tvCol)
Next
' Loop through rows To populate table
' Note how we keep track Of the row index:
' values belong To *columns*, so t' find them we ask a column to "go down X cells".
' Alternatively, we could keep track of the column position too,
' and use df.GetValue(colIndex, rowIndex), but it's more work.
For Each item In df.Rows.[Select](Function(row, index) New With {row, index
})
Dim tvr = New TableViewRow()
For Each col In df.Columns
' TableViews want strings everywhere, so we use GetValueAsString.
' In other situations, we could use GetValueAsObject and cast it to the right type.
Dim tvrc = tv.CreateColumn(col.Name, col.GetValueAsString(item.index), False, True)
tvr.Items.Add(col.Name, tvrc)
Next
tv.Rows.Add(tvr)
Next
Return tv
End Using
End If
End If
Return Nothing
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
Public Function TableViewGetCustomSubstVarsInUse(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, ByVal tableViewName As String, ByVal custSubstVarsAlreadyResolved As Dictionary(Of String, String)) _
As List(Of String) Implements IWsasTableViewV800.TableViewGetCustomSubstVarsInUse
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) Then
If tableViewName.XFEqualsIgnoreCase("DataFrame") Then
' implement this as you need
End If
End If
Return Nothing
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
Public Function SaveTableView(ByVal si As SessionInfo, ByVal brGlobals As BRGlobals, ByVal workspace As DashboardWorkspace, ByVal tableViewName As String, _
ByVal tableView As TableView) As Boolean Implements IWsasTableViewV800.SaveTableView
Try
If (brGlobals IsNot Nothing) AndAlso (workspace IsNot Nothing) AndAlso (tableView IsNot Nothing) Then
If tableViewName.XFEqualsIgnoreCase("DataFrame") Then
' implement this as you need
End If
End If
Return False
Catch ex As Exception
Throw New XFException(si, ex)
End Try
End Function
End Class
End Namespace


